#pragma once
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <set>
#include <jsoncpp/json/json.h>
#include "index.hpp"
#include "util.hpp"

class Searcher
{
private:
    NS_Index::Index* _index; // 供系统进行查找到索引
public:
    Searcher()
    {}
    ~Searcher()
    {}
    void InitSearcher(const std::string& src_path)
    {
        // 获取index对象
        _index = NS_Index::Index::GetInstance();
        std::cout << "get index instance success, build index begin..." << std::endl;
        // 建立索引
        _index->BuildIndex(src_path);
        std::cout << "build index begin success" << std::endl;
    }
    std::string GetDesc(std::string& content, const std::string& word)
    {
        // 忽略大小写查找，避免找不到的情况
        auto iter = std::search(content.begin(), content.end(), word.begin(), word.end(),
            [](char x, char y) {
                return tolower(x) == tolower(y);
            });
        if (iter == content.end())
            return "NONE";

        int pos = iter - content.begin(); // 转化查找位置

        // 确定开始和结束位置
        const int prev_step = 50; // 向前向后步长
        const int next_step = 100;

        int start = 0; // 起始结束默认值
        int end = content.size() - 1;

        // 从pos位置先前向后扩展step长度
        if (pos - prev_step >= start)
            start = pos - prev_step;
        if (pos + next_step < content.size())
            end = pos + next_step;

        // 截取子串并返回
        if (start > end)
            return "ERROR";
        return content.substr(start, end - start + 1);
    }

    /// @brief 搜索服务接口
    /// @param query 用户输入的数据
    /// @param json_string 返回给浏览器的结果
    void Search(const std::string& query, std::string* json_string)
    {
        /* 对query分词 */
        std::vector<std::string> words;
        Jieba::SpiltPhrase(query, &words);

        /* 对分出的多个关键词进行查找 */
        NS_Index::Index::InvertedList ivtd_list_v; // 保存所有关键字的所有倒排拉链

        for (auto word : words)
        {
            boost::to_lower(word);

            NS_Index::Index::InvertedList* ivtd_list = _index->GetInvertedList(word);
            if (ivtd_list == nullptr) {
                continue;
            }
            // 汇总到总倒排拉链中
            ivtd_list_v.insert(ivtd_list_v.end(), ivtd_list->begin(), ivtd_list->end());
        }

        /* 汇总所有查找结果，按照权重降序排序 */
        // 去重
        std::unordered_map<uint64_t, NS_Index::InvertedElem> unique_map;
        for (auto& e : ivtd_list_v) {
            auto& ret = unique_map[e._doc_id];
            ret._doc_id = e._doc_id;
            ret._weight += e._weight; // 如果存在可以，增加权重
        }

        // 降序排序
        std::sort(ivtd_list_v.begin(), ivtd_list_v.end(),
            [](const NS_Index::InvertedElem& e1, const NS_Index::InvertedElem& e2) {
                return e1._weight > e2._weight;
            });

        /* 将整体查找结果构建json序列化并返回 */
        // json对象
        Json::Value root;

        // 获取关键字对应文档信息
        for (auto& item : ivtd_list_v)
        {
            NS_Index::DocInfo* info = _index->GetDocInfo(item._doc_id);
            if (info == nullptr) {
                continue;
            }

            // 序列化
            Json::Value elem;
            elem["title"] = info->_title;
            elem["desc"] = GetDesc(info->_content, item._word);
            elem["url"] = info->_url;
            elem["docId"] = std::to_string(info->_doc_id);
            elem["weight"] = item._weight;

            root.append(elem);
        }

        Json::StyledWriter writer;
        *json_string = writer.write(root); // 获取json串
    }

};